#! /usr/bin/env python
# -*- coding: utf-8 -*-

# This script is licensed under the permissive MIT license.
# So have fun and go crazy -- we won't bug you.

# Copyright (c) 2009 Juan Pablo Di Lelle, Gijsbert de Haan
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

# This is Yahmon.
# Yahmon is the poor man's website monitoring script, I-ree.
# Yahmon tells you when your sites are down, without stressing too much.
# For more info, see http://yahmon.googlecode.com/ .

from datetime import datetime
import getopt
import smtplib
import sys
from urllib2 import Request, urlopen


class YahMon:

    def __init__(self, config):
        self.config = config

    def send_alert(self, sender, recipients, message):
        """
        Send an alert message.
        Assumes an SMTP server is running and properly configured.
        """

        session = smtplib.SMTP(self.config['SMTP_SERVER'],
                               self.config['SMTP_PORT'])
        if self.config['SMTP_AUTHENTICATION_REQUIRED']:
            session.login(self.config['SMTP_USER'], self.config['SMTP_PWD'])
        session.sendmail(sender, recipients, message.encode('utf-8',
                                                            'replace'))
        session.quit()

    def is_up(self, url, sender, recipients, content, template, log):
        """
        Tests whether the given URL can handle http requests and whether the
        response contains the given content.
        I'm a bit lazy as a script, so you must provide a valid URL
        starting with http:// or https://.
        """

        outcome = u""
        _in = datetime.now()
        req = Request(url)
        try:
            response = urlopen(req)
            if not content in response.read():
                outcome = self.config['CONTENT_NOT_FOUND']
        except IOError, e:
            if hasattr(e, 'reason'):
                outcome = u"%s %s" % (self.config['SERVER_NOT_RESPONDING'],
                                      e.reason)
            elif hasattr(e, 'code'):
                outcome = u"%s %s" % (self.config['SERVER_FAILED'], e.code)
            else:
                outcome = u"%s %s" % (self.config['CAUGHT_EXCEPTION'], e)
        except Exception, e:
            outcome = u"%s %s" % (self.config['CAUGHT_EXCEPTION'], e)

        _out = datetime.now()

        if outcome:
            message = template % (recipients, sender, url.upper(), url,
                                  outcome)
            self.send_alert(sender, recipients, message)
            up = False
        else:
            outcome = self.config['ALL_IS_GOOD_MON']
            up = True

        log.info('"%s", "%s", "%s", "%s", "%s"' % (url, _in, (_out-_in), up, outcome))

    def check_sites(self):
        """Check all the SITES to see if they are up."""
        for url, params in self.config['SITES'].iteritems():
            sender = params['sender']
            recipients = ','.join(params['recipients'])
            content = params['content']
            template = params['template']
            log = params['logger']
            self.is_up(url, sender, recipients, content, template, log)


class Usage(Exception):

    def __init__(self, msg):
        self.msg = msg


def main(argv=None):
    if argv is None:
        argv = sys.argv
    try:
        try:
            opts, args = getopt.getopt(argv[1:], "h", ["help"])
        except getopt.error, msg:
            raise Usage(msg)
        config = {}
        if not args:
            raise Usage("Please provide a configuration file.")
        try:
            for fn in args:
                execfile(fn, globals(), config)
        except IOError, e:
            raise Usage(e)

        # I CAN HAZ MON
        sys.exit(YahMon(config).check_sites())

    except Usage, e:
        print >>sys.stderr, e.msg
        return 2

if __name__ == "__main__":
    sys.exit(main())
